# coding:utf-8
'''
	渲染工具模块
	汉中库得网络科技
	电子信箱：yyc1030@qq.com
'''
import os
from PySide2 import QtCore
from PySide2 import QtGui
from PySide2 import QtWidgets
from pymxs import runtime as rt
# import MaxPlus

class RenderAction(QtWidgets.QAction):
	def __init__(self, app):
		self.app = app
		icon = QtGui.QIcon(app.rootPath + "/icon/render.png")
		super(RenderAction, self).__init__(icon, "批量渲染", app.mainWindow)
		self.setCheckable(True)
		self.triggered.connect(self.showRenderWindow)
		self.batchRenderWindow = None
		
	# 显示一键渲染对话框	
	@QtCore.Slot()
	def showRenderWindow(self):
		if self.isChecked():
			if not self.batchRenderWindow:
				self.batchRenderWindow = BatchRenderWindow(self.app)
			self.batchRenderWindow.show()
		else:
			self.batchRenderWindow.close()
		
# 批量渲染对话框
class BatchRenderWindow(QtWidgets.QMainWindow):
	def __init__(self, app):
		super(BatchRenderWindow, self).__init__(app.mainWindow)
		self.app = app
		self.setWindowIcon(app.logo)
		self.setWindowTitle("批量渲染")
		
		center = QtWidgets.QWidget()
		vbox = QtWidgets.QVBoxLayout()
		vbox.setSpacing(8)
		vbox.setMargin(8)
		
		# SliderBar
		self.sliderBar = SliderBar("渲染大小")
		self.sliderBar.setMinimum(10)
		self.sliderBar.setMaximum(100)
		self.sliderBar.setValue(100)
		self.sliderBar.changed.connect(self.renderSizeChanged)
		self.sliderBar.released.connect(self.renderSizeReleased)
		vbox.addWidget(self.sliderBar)
		# 渲染角度Label和添加相机按钮
		label = QtWidgets.QLabel("待渲染角度")
		addCameraButton = QtWidgets.QPushButton("所有相机")
		addCameraButton.clicked.connect(self.addAllCamera)
		hbox = QtWidgets.QHBoxLayout()
		hbox.addWidget(label)
		hbox.addWidget(addCameraButton)
		widget = QtWidgets.QWidget()
		widget.setLayout(hbox)
		vbox.addWidget(widget)
		# 相机列表
		self.cameraList = QtWidgets.QListWidget()
		self.cameraList.itemDoubleClicked.connect(self.onListItemDBClicked)
		vbox.addWidget(self.cameraList)
		
		# 保存类型
		vbox.addWidget(QtWidgets.QLabel("保存类型"))
		hbox = QtWidgets.QHBoxLayout()
		tif = QtWidgets.QRadioButton("tif")
		jpg = QtWidgets.QRadioButton("jpg")
		tga = QtWidgets.QRadioButton("tga")
		self.group = QtWidgets.QButtonGroup()
		self.group.addButton(tif, 1)
		self.group.addButton(jpg, 2)
		self.group.addButton(tga, 3)
		hbox.addWidget(tif)
		hbox.addWidget(jpg)
		hbox.addWidget(tga)
		tif.setChecked(True)
		widget = QtWidgets.QWidget()
		widget.setLayout(hbox)
		vbox.addWidget(widget)
		
		# 渲染结果保存位置
		vbox.addWidget(QtWidgets.QLabel("渲染结果保存于以下目录"))
		label = QtWidgets.QLabel(u"{}render\\".format(rt.maxFilePath))
		label.setToolTip(u"{}render\\".format(rt.maxFilePath))
		vbox.addWidget(label)
		# 渲染结束后是否关机
		self.isShutdown = QtWidgets.QCheckBox("渲染完成自动关机")
		vbox.addWidget(self.isShutdown)
		
		# 开始渲染按钮
		startRenderButton = QtWidgets.QPushButton("开始渲染")
		startRenderButton.clicked.connect(self.startRender)
		vbox.addWidget(startRenderButton)
		
		center.setLayout(vbox)
		self.setCentralWidget(center)
		
		# 设置窗口大小
		self.width = 250
		self.height = 400
		self.setMaximumSize(self.width, self.height)
		self.setMinimumSize(self.width, self.height)
		# self.setGeometry(35, 155, self.width, self.height)
		self.resize(self.width, self.height)
		
	# 当渲染大小的值改变时
	@QtCore.Slot()
	def renderSizeChanged(self, val):
		for i in range(self.cameraList.count()):
			item = self.cameraList.item(i)
			cameraWidget = self.cameraList.itemWidget(item)
			cameraWidget.setRatio(float(val) / 100)
			
	# 当松开滑块时
	@QtCore.Slot()
	def renderSizeReleased(self, val):
		pass
		
	# 当列表项被双击时
	def onListItemDBClicked(self, item):
		self.cameraList.takeItem(self.cameraList.row(item))
	
	# 添加场景中的所有相机
	def addAllCamera(self):
		# 先移除所有项
		while self.cameraList.count():
			self.cameraList.takeItem(0)
		
		for camera in rt.cameras:
			if not camera.name.endswith(".Target"):
				cameraItemWidget = CameraItemWidget(camera, float(self.sliderBar.value()) / 100)
				item = QtWidgets.QListWidgetItem(self.cameraList)
				item.setSizeHint(cameraItemWidget.sizeHint())
				self.cameraList.addItem(item)
				self.cameraList.setItemWidget(item, cameraItemWidget)
		
	# 开始批量渲染
	@QtCore.Slot()
	def startRender(self):
		# 如果渲染设置对话框是打开的，关闭它
		if rt.renderSceneDialog.isOpen():
			rt.renderSceneDialog.close()

		# 要加入渲染的相机列表
		list = self.getCameraItems()
		savePath = rt.maxFilePath + "render\\"
		if not os.path.exists(savePath):
			os.makedirs(savePath)
		# 开启保存文件
		rt.rendSaveFile = True
		# 解锁图像宽高比
		rt.rendLockImageAspectRatio = False
		# 获取渲染效果项管理者
		mgr = rt.maxOps.GetCurRenderElementMgr()
		# 获取用户设置了多少个Render Element
		elementNum = mgr.NumRenderElements()
		for item in list:
			# 激活最后一个viewport
			rt.viewport.activeViewport = rt.viewport.numViews
			# 显示安全框
			rt.displaySafeFrames = True
			# 设置相机
			rt.viewport.setCamera(item.camera)
			rt.redrawViews()
			# 设置保存位置
			extName = self.group.checkedButton().text()
			rt.rendOutputFilename = savePath + "%s.%s" % (item.camera.name, extName)
			# 设置宽高
			rt.renderWidth = item.getWidth()
			rt.renderHeight = item.getHeight()
			
			# 设置Render Element保存位置
			for i in range(0, elementNum):
				elmt = mgr.GetRenderElement(i)
				saveFile = savePath + "%s_%s.%s" % (item.camera.name, elmt.elementName, extName)
				mgr.SetRenderElementFilename(i, saveFile)
			
			#rt.render(outputfile=rt.rendOutputFilename)
			rt.execute("max quick render")
			
		# 关闭保存文件
		rt.rendSaveFile = False
		
		# 判断是否关机
		if self.isShutdown.isChecked():
			os.system("shutdown -s -t 10")
			
		
	# 获取所有待渲染的相机列表
	# @return List<CameraItemWidget>
	def getCameraItems(self):
		list = []
		for i in range(self.cameraList.count()):
			item = self.cameraList.item(i)
			cameraWidget = self.cameraList.itemWidget(item)
			list.append(cameraWidget)
		return list
	
	# 监听关闭事件
	def closeEvent(self, event):
		self.app.toolbar.renderAction.setChecked(False)
		
'''
	滑块栏
	包含一个标题Label，一个Slider组件，和一个显示Slider值的Label
	如果不传入title，则不包含标题Label
'''
class SliderBar(QtWidgets.QWidget):
	# 值变化信号
	changed = QtCore.Signal(int)
	# 松开滑块时的信息
	released = QtCore.Signal(int)
	
	def __init__(self, title=None):
		super(SliderBar, self).__init__()
		vbox = QtWidgets.QVBoxLayout()
		if title:
			titleLabel = QtWidgets.QLabel(title)
			vbox.addWidget(titleLabel)
		
		sliderWidget = QtWidgets.QWidget()
		hbox = QtWidgets.QHBoxLayout()
		self.slider = QtWidgets.QSlider()
		self.slider.setOrientation(QtCore.Qt.Horizontal)
		self.slider.valueChanged.connect(self.changedValue)
		self.slider.sliderReleased.connect(self.onReleased)
		self.slider.setToolTip("在最终渲染成图的基础上，按比例缩小渲染尺寸")
		hbox.addWidget(self.slider)
		
		self.sliderValLabel = QtWidgets.QLabel("100%")
		self.sliderValLabel.setMinimumWidth(30)
		self.sliderValLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
		
		hbox.addWidget(self.sliderValLabel)
		sliderWidget.setLayout(hbox)
		
		vbox.addWidget(sliderWidget)
		vbox.setSpacing(10)
		self.setLayout(vbox)
		
	@QtCore.Slot()
	def changedValue(self):
		val = self.slider.value()
		self.sliderValLabel.setText("{}%".format(val))
		self.changed.emit(val)
	
	@QtCore.Slot()
	def onReleased(self):
		self.released.emit(self.slider.value())
		
	def setMinimum(self, val):
		self.slider.setMinimum(val)
	
	def setMaximum(self, val):
		self.slider.setMaximum(val)
		
	def setValue(self, val):
		self.slider.setValue(val)
		self.sliderValLabel.setText("{}%".format(val))
		
	def value(self):
		return self.slider.value()
		
# 批量渲染窗口中，相机列表项组件
class CameraItemWidget(QtWidgets.QWidget):
	def __init__(self, camera, sizeRatio, parent=None):
		super(CameraItemWidget, self).__init__(parent)
		self.camera = camera
		self.label = QtWidgets.QLabel(camera.name)
		self.rLabel = QtWidgets.QLabel("未记录")
		self.rLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
		if rt.getUserPropVal(camera, "width"):
			self.__width = int(rt.getUserPropVal(camera, "width") * sizeRatio)
			self.__height = int(rt.getUserPropVal(camera, "height") * sizeRatio)
			self.rLabel.setText("%5d x%5d" % (self.__width, self.__height))
			
		hbox = QtWidgets.QHBoxLayout()
		hbox.addWidget(self.label)
		hbox.addWidget(self.rLabel)
		
		self.setToolTip("双击移除该项")
		self.setLayout(hbox)
		
	# 设置缩放比例
	# ratio 为0-1之间的float
	def setRatio(self, ratio):
		self.__width = int(rt.getUserPropVal(self.camera, "width") * ratio)
		self.__height = int(rt.getUserPropVal(self.camera, "height") * ratio)
		self.rLabel.setText("%5d x%5d" % (self.__width, self.__height))
		
	def getWidth(self):
		return self.__width
		
	def getHeight(self):
		return self.__height